// Created by Roman Novitsky on 09.07.2009


#region Imported Namespaces


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;


#endregion


namespace MobilePal.Controls
{
  public class NumericUpDownSlider: UpDownSliderBase<int>
  {
    #region Fields


    private readonly bool _isInitializing = true;
    private readonly List<Label> _labels = new List<Label>();
    private List<int> _digitValueChangeSteps = new List<int>();
    private Label _mouseDownLabel;
    private int _mouseDownY;
    private string _numberFormat;


    #endregion


    #region Constructors/Finalizers


    public NumericUpDownSlider()
    {
      MaxValue = 10;

      _isInitializing = false;

      Build();
    }


    #endregion


    #region Properties/Indexers


    public List<int> DigitValueChangeSteps
    {
      get
      {
        return _digitValueChangeSteps;
      }
      set
      {
        _digitValueChangeSteps = value;
      }
    }

    public override Font Font
    {
      get
      {
        return base.Font;
      }
      set
      {
        base.Font = value;

        Build();
      }
    }


    #endregion


    #region Methods


    protected override void OnThumbsBackgroundColorChanged()
    {
      foreach (Label label in _labels)
      {
        label.BackColor = ThumbsBackgroundColor;
      }
    }


    private void Build()
    {
      if (_isInitializing)
      {
        return;
      }

      string maxValue = MaxValue.ToString();

      _numberFormat = new string('0', maxValue.Length);

      SuspendLayout();

      SizeF textSize = this.GetTextSize("0", Font, 8);

      CreateLabels(maxValue, textSize);

      Controls.Clear();
      for (int i = 0; i < _labels.Count; i++)
      {
        Controls.Add(_labels[i]);
      }

      LayoutLabels();

      UpdateLabels();

      ResumeLayout(true);
    }


    private void LayoutLabels()
    {
      if (!_labels.Any())
      {
        return;
      }

      for (int i = 0; i < _labels.Count; i++)
      {
        Label label = _labels[i];

        int labelX = label.Width * i;

        if (i == 0)
        {
          labelX += Padding;
        }
        else
        {
          labelX += ThumbsPadding;
        }

        label.Location = new Point(labelX, Padding);
      }

      Label lastLabel = _labels.Last();

      int height = lastLabel.Height + Padding * 2;
      int width = lastLabel.Location.X + lastLabel.Width + Padding;

      Size = new Size(width, height);
    }


    private void CreateLabels(string count, SizeF textSize)
    {
      _labels.Clear();

      for (int i = 0; i < count.Length; i++)
      {
        var label = new Label();
        label.SuspendLayout();

        label.Font = Font;
        label.Size = new Size((int)textSize.Width, (int)textSize.Height);
        label.BackColor = ThumbsBackgroundColor;
        label.TextAlign = ContentAlignment.TopCenter;

        label.ResumeLayout(true);
        label.Name = "label" + i;

        _labels.Add(label);
      }
    }


    protected override bool IsLower(int value1, int value2)
    {
      return value1 < value2;
    }


    protected override bool IsGreater(int value1, int value2)
    {
      return value1 > value2;
    }


    protected override int Add(int value, int amount)
    {
      int newValue = value + amount;

      newValue = GetValidValue(value, newValue, amount);

      return newValue;
    }


    private int GetValidValue(int originalValue, int newValue, int delta)
    {
      if (newValue > MaxValue)
      {
        int delta1 = MaxValue - originalValue;
        int delta2 = delta - delta1 - 1;

        newValue = MinValue + delta2;
      }

      if (newValue < MinValue)
      {
        int delta1 = originalValue - MinValue;
        int delta2 = delta - delta1 - 1;

        newValue = MaxValue - delta2;
      }
      return newValue;
    }


    protected override int Subtract(int value, int amount)
    {
      int newValue = value - amount;

      newValue = GetValidValue(value, newValue, amount);

      return newValue;
    }


    protected override void OnMaxValueChanged()
    {
      Build();
    }


    protected override void OnResize(EventArgs e)
    {
      LayoutLabels();
    }


    protected override void OnThumbsPaddingChanged()
    {
      LayoutLabels();
    }


    protected override void OnPaddingChanged()
    {
      LayoutLabels();
    }


    private void UpdateLabels()
    {
      string value = Value.ToString(_numberFormat);

      for (int i = 0; i < _labels.Count; i++)
      {
        _labels[i].Text = value[i].ToString();
      }
    }


    protected override void OnMouseDown(MouseEventArgs e)
    {
      _mouseDownY = e.Y;

      Point screen = PointToScreen(new Point(e.X, e.Y));

      _mouseDownLabel = GetMouseDownTextBox(screen);

      if (_mouseDownLabel != null)
      {
        _mouseDownLabel.BackColor = ThumbsDownColor;
      }
    }


    protected override void OnMouseMove(MouseEventArgs e)
    {
      if (_mouseDownLabel == null)
      {
        return;
      }

      int mouseMoveDistance = _mouseDownY - e.Y;

      if (Math.Abs(mouseMoveDistance) <= SlideDistance)
      {
        return;
      }

      _mouseDownY = e.Y;

      int digitIndex = _labels.IndexOf(_mouseDownLabel);
      int delta = GetDefaultDelta(digitIndex);

      if (_digitValueChangeSteps != null && _digitValueChangeSteps.Any())
      {
        if (digitIndex < _digitValueChangeSteps.Count)
        {
          delta = _digitValueChangeSteps[digitIndex];
        }
      }

      if (mouseMoveDistance < 0)
      {
        DecreaseValue(delta);
      }
      else if (mouseMoveDistance > 0)
      {
        IncreaseValue(delta);
      }

      return;
    }


    private int GetDefaultDelta(int digitIndex)
    {
      int indexOf = _labels.Count - (digitIndex + 1);
      var delta = (int)Math.Pow(10, indexOf);

      return delta;
    }


    private Label GetMouseDownTextBox(Point screen)
    {
      foreach (Label textBox in _labels)
      {
        Point client = textBox.PointToClient(screen);

        if (client.X > 0 && client.X < textBox.Width && client.Y > 0 && client.Y < textBox.Height)
        {
          return textBox;
        }
      }

      return null;
    }


    protected override void OnMouseUp(MouseEventArgs e)
    {
      foreach (Label textBox in _labels)
      {
        textBox.BackColor = ThumbsBackgroundColor;
      }

      _mouseDownLabel = null;
    }


    protected override void OnValueChanged()
    {
      UpdateLabels();
    }


    #endregion
  }
}